ostree repo commit: Speed up composing trees with `--tree=ref`
authorWilliam Manley <will@williammanley.net>
Fri, 22 Jun 2018 14:28:49 +0000 (15:28 +0100)
committerAtomic Bot <atomic-devel@projectatomic.io>
Mon, 9 Jul 2018 13:10:51 +0000 (13:10 +0000)
commitc7b12a8730260c66bc96363a3a3c5805b325bac8
treeec4a54c682086e324442e34aad2979ce365486c2
parent11eb0bd227ffa1a3300e4dbde3da288a7d9d41ae
ostree repo commit: Speed up composing trees with `--tree=ref`

Running `ostree commit --tree=ref=a --tree=dir=b` involves reading the
whole of a into an `OstreeMutableTree` before composing `b` on top.  This
is inefficient if a is a complete rootfs and b is just touching one file.
We process O(size of a + size of b) directories rather than
O(number of touched dirs).

This commit makes `ostree commit` more efficient at composing multiple
directories together.  With `ostree_mutable_tree_fill_empty_from_dirtree`
we create a lazy `OstreeMutableTree` which only reads the underlying
information from disk when needed.  We don't need to read all the
subdirectories just to get the checksum of a tree already checked into the
repo.

This provides great speedups when composing a rootfs out of multiple other
rootfs as we do in our build system.  We compose multiple containers
together with:

    ostree commit --tree=ref=base-rootfs --tree=ref=container1 --tree=ref=container2

and it is much faster now.

As a test I ran

    time ostree --repo=... commit --orphan --tree=ref=big-rootfs --tree=dir=modified_etc

Where modified_etc contained a modified sudoers file under /etc.  I used
`strace` to count syscalls and I seperatly took timing measurements.  To
test with a cold cache I ran

    sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

Results:

|                      | Before | After |
| -------------------- | ------ | ----- |
| Time (cold cache)    |   8.1s | 0.12s |
| Time (warm cache)    |   3.7s | 0.08s |
| `openat` calls       |  53589 |   246 |
| `fgetxattr` calls    |  78916 |     0 |

I'm not sure if this will have some negative interaction with the
`_ostree_repo_commit_modifier_apply` which is short-circuited here.  I
think it was disabled for `--tree=ref=` anyway, but I'm not certain.  All
the tests pass anyway.

I originally implemented this in terms of the `OstreeRepoFile` APIs, but
it was *way* less efficient, opening and reading many files unnecessarily.

Closes: #1643
Approved by: cgwalters
apidoc/ostree-sections.txt
src/libostree/libostree-devel.sym
src/libostree/ostree-mutable-tree.c
src/libostree/ostree-mutable-tree.h
src/libostree/ostree-repo-commit.c